//
// Copyright (C) 2011 - 2013  Steve Channell steve.channell@cepheis.com
//
// This file is part of Cephei.QL, an open-source library wrapper 
// arround QuantLib http://quantlib.org/
//
// Cephei.QL is open source software: you can redistribute it and/or modify it
// under the terms of the license.  You should have received a
// copy of the license along with this program; if not, please email
// <support@cepheis.com>. The license is also available online at
// <http://cepheis.com/license.htm>.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the license for more details.
//
// Version 2.2 with QuantLib 1.2.1
//#include "stdafx.h"
#include "FixedRateLeg.h"
using namespace Cephei::QL::Cashflows;
#include <gen/QL/CashFlow.h>
#include <gen/QL/InterestRate.h>
#include <gen/QL/Times/DayCounter.h>
#include <gen/QL/Times/Schedule.h>
#include <gen/QL/Times/Calendar.h>
using namespace Cephei::QL;
using namespace Cephei::QL::Times;
#undef HANDLE
#undef ABSTRACT
#undef STRUCT
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (Cephei::QL::Times::ISchedule^ schedule) 
{
	_pSpinlock = new boost::detail::spinlock ();
    CSchedule^ _Cschedule;
    try
    {
#ifdef HANDLE
        _phFixedRateLeg = NULL;
#endif
        _Cschedule = safe_cast<CSchedule^> (schedule);
        _Cschedule->Lock();
        QuantLib::Schedule& _schedule = static_cast<QuantLib::Schedule&> (_Cschedule->GetReference ()); 
        _ppFixedRateLeg = new boost::shared_ptr<QuantLib::FixedRateLeg> (new QuantLib::FixedRateLeg ( _schedule ));
        
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (_Cschedule != nullptr) _Cschedule->Unlock();
    }
}
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (boost::shared_ptr<QuantLib::FixedRateLeg>& childNative, Object^ owner) 
{
	_pSpinlock = new boost::detail::spinlock ();
#ifdef HANDLE
	_phFixedRateLeg = NULL;
#endif
	_ppFixedRateLeg = &childNative;
    
}
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (QuantLib::FixedRateLeg& childNative, Object^ owner) 
{
#ifdef HANDLE
	_phFixedRateLeg = NULL;
#endif
	_ppFixedRateLeg = new boost::shared_ptr<QuantLib::FixedRateLeg> (&childNative);
    
    _FixedRateLegOwner = owner;
    
}

Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (CFixedRateLeg^ copy) 
{
	_pSpinlock = new boost::detail::spinlock ();
#ifdef HANDLE
	_phFixedRateLeg = NULL;
#endif
	if (copy->HasNative() != NULL)
    {
		_ppFixedRateLeg = new boost::shared_ptr<QuantLib::FixedRateLeg> (copy->GetShared());
        
    }
}
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (PLATFORM::Type^ t) 
{
	_pSpinlock = new boost::detail::spinlock ();
#ifdef HANDLE
	_phFixedRateLeg = NULL;
#endif
	if (!t->IsSubclassOf(CFixedRateLeg::typeid))
		throw REFNEW Exception ("Invalid base-case init");
}
#ifdef HANDLE
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (QuantLib::Handle<QuantLib::FixedRateLeg>& childNative, Object^ owner)  
{
	_pSpinlock = new boost::detail::spinlock ();
	_phFixedRateLeg = &childNative;
	_ppFixedRateLeg = &static_cast<boost::shared_ptr<QuantLib::FixedRateLeg>>(childNative.currentLink());
    
    _FixedRateLegOwner = owner;
}
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (QuantLib::Handle<QuantLib::FixedRateLeg> childNative)  
{
	_pSpinlock = new boost::detail::spinlock ();
	_phFixedRateLeg = &childNative;
	_ppFixedRateLeg = &static_cast<boost::shared_ptr<QuantLib::FixedRateLeg>>(childNative.currentLink());
    
}
#endif
#ifdef STRUCT
Cephei::QL::Cashflows::CFixedRateLeg::CFixedRateLeg (QuantLib::FixedRateLeg childNative)  
{
	_pSpinlock = new boost::detail::spinlock ();
#ifdef HANDLE
	_phFixedRateLeg = NULL;
#endif
	_ppFixedRateLeg = new boost::shared_ptr<QuantLib::FixedRateLeg> (new QuantLib::FixedRateLeg (childNative));
    
}
#endif

Cephei::QL::Cashflows::CFixedRateLeg::~CFixedRateLeg ()
{
	if (_pSpinlock != NULL)
    {
        delete _pSpinlock;
        _pSpinlock = NULL;
    }
    if (_ppFixedRateLeg != NULL)
    {
	    delete _ppFixedRateLeg;
        _ppFixedRateLeg = NULL;
    }
}
Cephei::QL::Cashflows::CFixedRateLeg::!CFixedRateLeg ()
{
	if (_pSpinlock != NULL)
    {
        delete _pSpinlock;
    }
    if (_ppFixedRateLeg != NULL)
    {
	    delete _ppFixedRateLeg;
    }
}
QuantLib::FixedRateLeg& Cephei::QL::Cashflows::CFixedRateLeg::GetReference ()
{
    if (_ppFixedRateLeg == NULL) throw REFNEW NativeNullException ();
	return **_ppFixedRateLeg;
}
boost::shared_ptr<QuantLib::FixedRateLeg>& Cephei::QL::Cashflows::CFixedRateLeg::GetShared ()
{
    if (_ppFixedRateLeg == NULL) throw REFNEW NativeNullException ();
	return *_ppFixedRateLeg;
}
QuantLib::FixedRateLeg* Cephei::QL::Cashflows::CFixedRateLeg::GetPointer ()
{
    if (_ppFixedRateLeg == NULL) throw REFNEW NativeNullException ();
	return &**_ppFixedRateLeg;
}
#ifdef HANDLE
QuantLib::Handle<QuantLib::FixedRateLeg>& Cephei::QL::Cashflows::CFixedRateLeg::GetHandle ()
{
	if (_phFixedRateLeg == NULL)
	{
		_phFixedRateLeg = new Handle<QuantLib::FixedRateLeg> (*_ppFixedRateLeg);
	}
	return *_phFixedRateLeg;
}
#endif
bool Cephei::QL::Cashflows::CFixedRateLeg::HasNative () 
{
	return (_ppFixedRateLeg != NULL);
}

Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithCouponRates (Cephei::Core::IVector<Cephei::QL::IInterestRate^>^ prm1)
{
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        prm1->Lock();
        INativeVector<Cephei::QL::IInterestRate^>^ _NCIprm1 = prm1->getFeature (NativeFeature::Value);
        CInterestRateVector^ _NCprm1 = safe_cast<CInterestRateVector^>(_NCIprm1);
        std::vector<QuantLib::InterestRate>& _prm1 = static_cast<std::vector<QuantLib::InterestRate>&> (_NCprm1->GetReference ());
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withCouponRates ( _prm1 );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (prm1 != nullptr) prm1->Unlock(); //NO2  
    }
}
Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithFirstPeriodDayCounter (Cephei::QL::Times::IDayCounter^ dayCounter)
{
    CDayCounter^ _CdayCounter;
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        _CdayCounter = safe_cast<CDayCounter^> (dayCounter);
        _CdayCounter->Lock();
        QuantLib::DayCounter& _dayCounter = static_cast<QuantLib::DayCounter&> (_CdayCounter->GetReference ()); 
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withFirstPeriodDayCounter ( _dayCounter );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (_CdayCounter != nullptr) _CdayCounter->Unlock();
    }
}
Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithNotionals (Cephei::Core::IVector<Double>^ prm1)
{
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        prm1->Lock();
        INativeVector<Double>^ _NCIprm1 = prm1->getFeature (NativeFeature::Value);
        CDoubleVector^ _NCprm1 = safe_cast<CDoubleVector^>(_NCIprm1);
        std::vector<QuantLib::Real>& _prm1 = static_cast<std::vector<QuantLib::Real>&> (_NCprm1->GetReference ());
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withNotionals ( _prm1 );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (prm1 != nullptr) prm1->Unlock(); //NO2  
    }
}
Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithPaymentAdjustment (QL::Times::BusinessDayConventionEnum convention)
{
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        QuantLib::BusinessDayConvention _convention = (QuantLib::BusinessDayConvention)convention ;
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withPaymentAdjustment ( _convention );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithCouponRates (Cephei::Core::IVector<Double>^ prm1, Cephei::QL::Times::IDayCounter^ paymentDayCounter, Microsoft::FSharp::Core::FSharpOption<QL::CompoundingEnum>^ comp, Microsoft::FSharp::Core::FSharpOption<QL::Times::FrequencyEnum>^ freq)
{
    CDayCounter^ _CpaymentDayCounter;
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        prm1->Lock();
        INativeVector<Double>^ _NCIprm1 = prm1->getFeature (NativeFeature::Value);
        CDoubleVector^ _NCprm1 = safe_cast<CDoubleVector^>(_NCIprm1);
        std::vector<QuantLib::Rate>& _prm1 = static_cast<std::vector<QuantLib::Rate>&> (_NCprm1->GetReference ());
        _CpaymentDayCounter = safe_cast<CDayCounter^> (paymentDayCounter);
        _CpaymentDayCounter->Lock();
        QuantLib::DayCounter& _paymentDayCounter = static_cast<QuantLib::DayCounter&> (_CpaymentDayCounter->GetReference ()); 
        QuantLib::Compounding _comp = 
            (Microsoft::FSharp::Core::FSharpOption<QL::CompoundingEnum>::IsSome::get (comp) ? (QuantLib::Compounding)comp->Value : QuantLib::Simple ); //5
        QuantLib::Frequency _freq = 
            (Microsoft::FSharp::Core::FSharpOption<QL::Times::FrequencyEnum>::IsSome::get (freq) ? (QuantLib::Frequency)freq->Value : QuantLib::Annual ); //5
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withCouponRates ( _prm1,  _paymentDayCounter,  _comp,  _freq );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (prm1 != nullptr) prm1->Unlock(); //NO2  
        if (_CpaymentDayCounter != nullptr) _CpaymentDayCounter->Unlock();
    }
}
Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg::WithPaymentCalendar (Cephei::QL::Times::ICalendar^ cal)
{
    CCalendar^ _Ccal;
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        _Ccal = safe_cast<CCalendar^> (cal);
        _Ccal->Lock();
        QuantLib::Calendar& _cal = static_cast<QuantLib::Calendar&> (_Ccal->GetReference ()); 
    	QuantLib::FixedRateLeg& _rv = (QuantLib::FixedRateLeg&)(*_ppFixedRateLeg)->withPaymentCalendar ( _cal );   
        Cephei::QL::Cashflows::CFixedRateLeg^ _nrv = REFNEW Cephei::QL::Cashflows::CFixedRateLeg (_rv, this);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String(_error.what()));
        else
		    throw REFNEW NativeExcpetion (REFNEW PLATFORM::String("Unknown std::exception"));
	}
    finally
    {
        if (_Ccal != nullptr) _Ccal->Unlock();
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory class

Cephei::QL::Cashflows::IFixedRateLeg^ Cephei::QL::Cashflows::CFixedRateLeg_Factory::Create (Cephei::QL::Times::ISchedule^ schedule)
{
    return REFNEW CFixedRateLeg ( schedule);
}
